package com.lambkit.core.service;

import cn.hutool.core.util.ReflectUtil;
import com.lambkit.core.BeanContainer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yangyong(孤竹行)
 */
public abstract class AbstractBeanFactory implements BeanFactory {

    private BeanContainer beanContainer = new BeanContainer();

    public abstract <T> T newInstance(Class<T> clazz);

    @Override
    public <T> T get(Class<T> clazz) {
        T bean = beanContainer.getBean(clazz);
        if(bean == null && clazz != null && !clazz.isInterface()) {
            bean = newInstance(clazz);
            beanContainer.addBean(clazz, bean);
        }
        return bean;
    }

    @Override
    public <T> void set(Class<T> clazz, T bean) {
        beanContainer.addBean(clazz, bean);
    }

    @Override
    public <T> void set(Class<T> interfaceClass, Class<? extends T>... implementClass) {
        beanContainer.addImpl(interfaceClass, implementClass);
    }

    @Override
    public <T> T getBean(Class<T> clazz) throws Exception {
        return beanContainer.getBean(clazz);
    }

    @Override
    public <T> Map<String, T> getBeansMapOfType(Class<T> type) throws Exception {
        Class<?>[] beanImplClassArray = beanContainer.getImpl(type);
        if(beanImplClassArray != null) {
            Map<String, T> beanMap = new HashMap<>(1);
            for (Class<?> beanImplClass : beanImplClassArray) {
                if(beanImplClass != null) {
                    T bean = (T) get(beanImplClass);
                    if(bean != null) {
                        beanMap.put(beanImplClass.getName(), bean);
                    }
                }
            }
            return beanMap;
        }
        return null;
    }

    @Override
    public <T> List<T> getBeansOfType(Class<T> type) throws Exception {
        Class<?>[] beanImplClassArray = beanContainer.getImpl(type);
        if(beanImplClassArray != null) {
            List<T> beans = new ArrayList<>(1);
            for (Class<?> beanImplClass : beanImplClassArray) {
                if(beanImplClass != null) {
                    T bean = (T) get(beanImplClass);
                    if(bean != null) {
                        beans.add(bean);
                    }
                }
            }
            return beans;
        }
        return null;
    }
}
